
namespace Core
{
    using System;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text.RegularExpressions;
    using Contracts.Enums;
    using Contracts.Interfaces;

    /// <summary>
    /// Regular text formatted fitting importer
    /// </summary>
    public sealed class TextFittingImporter : IFittingImporter
    {
        private const string REGEX_FITTING = @"(?:\[)(?<robot>.*)\,(?<description>.*)(?:\])";

        /// <summary>
        /// Determines if the fitting value is valid
        /// </summary>
        /// <param name="value">A string representation of the fitting</param>
        /// <returns></returns>
        public bool IsValid(string value)
        {
            return Regex.IsMatch(value, REGEX_FITTING);
        }
        /// <summary>
        /// Imports and return a new instance of IFitting
        /// </summary>
        /// <param name="value">A string representation of an IFitting</param>
        /// <param name="repository">An IRepository instance</param>
        /// <returns>A new instance of IFitting or null</returns>
        public IFitting Import(string value, IRepository repository)
        {
            if (string.IsNullOrEmpty(value) || repository == null) return null;

            var match = Regex.Match(value, REGEX_FITTING);
            if (!match.Success) return null;

            string robotName = match.Groups["robot"].Success ? match.Groups["robot"].Value : null;
            string fittingDescription = match.Groups["description"].Success ? match.Groups["description"].Value.Trim() : null;

            if (string.IsNullOrEmpty(robotName)) return null;

            var bot = repository.Robots.Where(r => String.Equals(r.Name,robotName,StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
            if (bot == null) return null;

            var fitting = new Fitting(string.IsNullOrEmpty(fittingDescription) ? bot.Name : fittingDescription, (IRobot)bot.Clone());

            var parts = value.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length > 0)
            {
                for (int i = 1; i < parts.Length; i++) // skip first line already parsed
                {
                    if (string.IsNullOrEmpty(parts[i])) continue;

                    IModule module = GetModule(parts[i],repository);
                    if (module == null) continue;

                    fitting.Robot.AddModule(module, false);
                }
            }

            return fitting;
        }

        /// <summary>
        /// Parse the content and returns an instance of IModule or null
        /// </summary>
        /// <param name="value">The string content</param>
        /// <param name="repository">An IRepository instance</param>
        /// <returns>A new instance of IModule or null</returns>
        static IModule GetModule(string value, IRepository repository)
        {
            if (string.IsNullOrEmpty(value)|| repository ==null) return null;
            var parts = value.Split(',');
            if (parts == null || parts.Length == 0) return null;

            IModule module = repository.Modules
                .Where(m => string.Equals(parts[0], m.Name, StringComparison.InvariantCultureIgnoreCase))
                .FirstOrDefault();

            if (module == null) return null;

            module.IsNotifying = false;

            LoadUsableAmmunitions(module, repository);

            if(parts.Length > 1)
                module.Ammunitions = repository.Ammunitions
                    .Where( a =>  string.Equals(a.Name,parts[1].Trim(), StringComparison.InvariantCultureIgnoreCase) )
                    .FirstOrDefault();

            module.IsNotifying = true;
            return module;
        }

        /// <summary>
        /// Loads all ammunitions types usable by a module
        /// </summary>
        /// <param name="module">An IModule instance</param>
        /// <param name="repository">An IRepository instance</param>
        static void LoadUsableAmmunitions(IModule module, IRepository repository)
        {
            if (module == null || !module.CanHaveAmmunitions || module.UsableAmmunitions != null) return;

            var ammoType = module.Features.Where(f => f.FeatureType == FeaturesEnum.AmmoType).FirstOrDefault();
            if (ammoType == null) return;

            var ammos = repository.Ammunitions.Where(a => a.Type == (AmmunitionTypesEnum) ammoType.Value);
            if (!ammos.Any()) return;

            module.UsableAmmunitions =
                new ObservableCollection<IAmmunition>(new[] { NullAmmunition.Instance }.Union(ammos.Select(a => (IAmmunition)a.Clone())));
        }
    }
}